/*
Copyright 2007 Luke Benstead

This file is part of slMath.

slMath is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

slMath is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser Public License for more details.

You should have received a copy of the GNU Lesser Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef QUATERNION_H_INCLUDED
#define QUATERNION_H_INCLUDED

#ifdef USE_DOUBLE_PRECISION
	typedef double slScalar;
#else
	typedef float slScalar;
#endif

struct slVec3;
struct slMat4;

struct slQuaternion {
	slScalar m_X;
	slScalar m_Y;
	slScalar m_Z;
	slScalar m_W;
};



slQuaternion* slQuaternionConjugate(slQuaternion* pOut,
											const slQuaternion* pIn); ///< Returns pOut, sets pOut to the conjugate of pIn



slScalar 	slQuaternionDot(const slQuaternion* q1,
											const slQuaternion* q2); ///< Returns the dot product of the 2 quaternions



slQuaternion* slQuaternionExp(slQuaternion* pOut, const slQuaternion* pIn); ///< Returns the exponential of the quaternion

///< Makes the passed quaternion an identity quaternion

slQuaternion* slQuaternionIdentity(slQuaternion* pOut);

///< Returns the inverse of the passed Quaternion

slQuaternion* slQuaternionInverse(slQuaternion* pOut,
											const slQuaternion* pIn);

///< Returns true if the quaternion is an identity quaternion

bool slQuaternionIsIdentity(const slQuaternion* pIn);

///< Returns the length of the quaternion

slScalar slQuaternionLength(const slQuaternion* pIn);

///< Returns the length of the quaternion squared (prevents a sqrt)

slScalar slQuaternionLengthSq(const slQuaternion* pIn);

///< Returns the natural logarithm

slQuaternion* slQuaternionLn(slQuaternion* pOut, const slQuaternion* pIn);

///< Multiplies 2 quaternions together

slQuaternion* slQuaternionMultiply(slQuaternion* pOut,
								 const slQuaternion* q1,
								 const slQuaternion* q2);

///< Normalizes a quaternion

slQuaternion* slQuaternionNormalize(slQuaternion* pOut,
											const slQuaternion* pIn);

///< Rotates a quaternion around an axis

slQuaternion* slQuaternionRotationAxis(slQuaternion* pOut,
									const slVec3* pV,
									slScalar angle);

///< Creates a quaternion from a rotation matrix

slQuaternion* slQuaternionRotationMatrix(slQuaternion* pOut,
										const slMat4* pIn);

///< Create a quaternion from yaw, pitch and roll

slQuaternion* slQuaternionRotationYawPitchRoll(slQuaternion* pOut,
												slScalar yaw,
												slScalar pitch,
												slScalar roll);
///< Interpolate between 2 quaternions

slQuaternion* slQuaternionSlerp(slQuaternion* pOut,
								const slQuaternion* q1,
								const slQuaternion* q2,
								slScalar t);

///< Get the axis and angle of rotation from a quaternion

void slQuaternionToAxisAngle(const slQuaternion* pIn,
								slVec3* pVector,
								slScalar* pAngle);

///< Scale a quaternion

slQuaternion* slQuaternionScale(slQuaternion* pOut,
										const slQuaternion* pIn,
										slScalar s);


slQuaternion* slQuaternionAssign(slQuaternion* pOut, const slQuaternion* pIn);
slQuaternion* slQuaternionAdd(slQuaternion* pOut, const slQuaternion* pQ1, const slQuaternion* pQ2);

#endif
